package org.mozhu.mboot.admin.system.group.web.controller;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.mozhu.mboot.admin.system.account.entity.User;
import org.mozhu.mboot.admin.system.account.service.UserService;
import org.mozhu.mboot.admin.system.group.entity.Group;
import org.mozhu.mboot.admin.system.group.entity.GroupType;
import org.mozhu.mboot.admin.system.group.entity.UserGroupRelation;
import org.mozhu.mboot.admin.system.group.service.GroupService;
import org.mozhu.mboot.admin.system.group.service.UserGroupRelationService;
import org.mozhu.mboot.core.data.SearchFilters;
import org.mozhu.mboot.core.data.Searchable;
import org.mozhu.mboot.core.data.filter.Operator;
import org.mozhu.mboot.core.data.filter.SearchFilter;
import org.mozhu.mboot.core.security.Permissions;
import org.mozhu.mboot.core.support.datatable.DTReturnObject;
import org.mozhu.mboot.core.support.datatable.DTUtils;
import org.mozhu.mboot.core.util.BeanUtils;
import org.mozhu.mboot.core.util.MessageUtils;
import org.mozhu.mboot.core.web.AjaxResponse;
import org.mozhu.mboot.core.web.Constants;
import org.mozhu.mboot.core.web.bind.annotation.ControllerDefaults;
import org.mozhu.mboot.core.web.bind.annotation.PageableDefaults;
import org.mozhu.mboot.core.web.controller.BaseCRUDController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RequestMapping("/system/group/relation/user")
@Controller
@ControllerDefaults(resourceIdentity = "system:group")
public class UserGroupRelationController extends BaseCRUDController<UserGroupRelation, Long> {

    protected static final String BATCH_ADD_SUCCESS = "op.batch.add.success";

    @Autowired
    GroupService groupService;

    @Autowired
    UserService userService;

    protected UserGroupRelationService getBaseService() {
        return (UserGroupRelationService) baseService;
    }

    @Override
    protected void setCommonData(Model model) {
        super.setCommonData(model);
        model.addAttribute("types", GroupType.values());
    }

    @RequestMapping(value = "/{group}/list", method = RequestMethod.GET)
    public String listGroupRelation(HttpServletRequest request, Model model, @PathVariable("group") Group group) {
        if (this.permissions != null) {
            this.permissions.assertHasReadPermission();
        }
        setCommonData(model);
        return viewName("list");
    }

    @RequestMapping(value = "/{group}/list", headers = "ajax=true", method = RequestMethod.POST)
    @ResponseBody
    @PageableDefaults(sort = "id=desc")
    public Object listGroupRelationAjax(HttpServletRequest request, @PathVariable("group") Group group, Searchable searchable) {
        if (this.permissions != null) {
            this.permissions.assertHasReadPermission();
        }
        searchable.addSearchFilter("groupId", Operator.EQ, group.getId());
        Page<UserGroupRelation> page = getBaseService().findAll(searchable);
        DTReturnObject<UserGroupRelation> dtReturnObject = DTUtils.toDTReturnObject(page);
        dtReturnObject.setDraw(request.getParameter("draw"));
        dtReturnObject.setExtraData(getExtraDataWithRelations(request, page));
        return dtReturnObject;
    }

    private Map<String, Object> getExtraDataWithRelations(HttpServletRequest request, Page<UserGroupRelation> page) {
        Map<String, Object> extraDataMap = Maps.newHashMap();
        List<UserGroupRelation> groupRelationList = page.getContent();
        extraDataMap.put("users", getUsers(groupRelationList));
        extraDataMap.put("groups", getGroups(groupRelationList));
        return extraDataMap;
    }

    private Object getGroups(List<UserGroupRelation> groupRelationList) {
        Set<Long> groupIds = groupRelationList.stream().map(a -> a.getGroupId()).collect(Collectors.toSet());
        return groupService.findAllById(groupIds).stream().collect(Collectors.toMap(Group::getId, c -> BeanUtils.transBean2Map(c, "id", "name")));
    }

    private Object getUsers(List<UserGroupRelation> groupRelationList) {
        Set<Long> userIds = groupRelationList.stream().filter(a -> a.getUserId() != null).map(a -> a.getUserId()).collect(Collectors.toSet());
        return userService.findAllById(userIds).stream().collect(Collectors.toMap(User::getId, c -> BeanUtils.transBean2Map(c, "id", "name")));
    }

    @RequestMapping(value = "{group}/batch/delete", method = {RequestMethod.GET, RequestMethod.POST})
    public String batchDeleteGroupRelation(@PathVariable("group") Group group, @RequestParam("ids") Long[] ids, @RequestParam(value = Constants.BACK_URL, required = false) String backURL,
                                           RedirectAttributes redirectAttributes) {
        if (this.permissions != null) {
            this.permissions.assertHasDeletePermission();
        }
        getBaseService().deleteInBatch(ids);
        redirectAttributes.addFlashAttribute(Constants.MESSAGE, DELETE_SUCCESS);
        return redirect(backURL);
    }

    // -- ajax batch delete -- //
    @RequestMapping(headers = "ajax=true", value = "{group}/batch/delete", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Object batchDeleteGroupRelation(@PathVariable("group") Group group, @RequestParam("ids") Long[] ids) {
        try {
            if (this.permissions != null) {
                this.permissions.assertHasDeletePermission();
            }
            getBaseService().deleteInBatch(ids);
            return AjaxResponse.success(MessageUtils.message(DELETE_SUCCESS));
        } catch (RuntimeException e) {
            logger.error("batch delete fail", e);
            return AjaxResponse.fail(MessageUtils.message(DELETE_FAIL));
        }
    }

    @RequestMapping(value = "{group}/batch/append", method = RequestMethod.GET)
    public String showBatchAppendGroupRelationForm(@PathVariable("group") Group group, Model model) {
        if (this.permissions != null) {
            this.permissions.assertHasAnyPermission(new String[]{Permissions.CREATE_PERMISSION, Permissions.UPDATE_PERMISSION});
        }
        setCommonData(model);
        return viewName("appendRelation");
    }

    @RequestMapping(value = "{group}/batch/append", method = RequestMethod.POST)
    public String batchAppendGroupRelation(@PathVariable("group") Group group, @RequestParam("ids") Long[] ids, @RequestParam(value = Constants.BACK_URL, required = false) String backURL,
                                           RedirectAttributes redirectAttributes) {
        if (this.permissions != null) {
            this.permissions.assertHasAnyPermission(new String[]{Permissions.CREATE_PERMISSION, Permissions.UPDATE_PERMISSION});
        }
        Long groupId = group.getId();
        getBaseService().appendRelationToUser(groupId, Sets.newHashSet(ids));
        redirectAttributes.addFlashAttribute(Constants.MESSAGE, BATCH_ADD_SUCCESS);
        return redirect(backURL);
    }
}